1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4
5
6 public class AI : MonoBehaviour {
7
8 public Transform target;
9
10 private List<TileManager.Tile> tiles = new List<TileManager.Tile>();
11 private TileManager manager;
12 public GhostMove ghost;
13
14 public TileManager.Tile nextTile = null;
15 public TileManager.Tile targetTile;
16 TileManager.Tile currentTile;
17
18 void Awake()
19 {
20 manager = GameObject.Find("Game Manager").GetComponent<TileManager>();
21 tiles = manager.tiles;
22
23 if(ghost == null) Debug.Log ("game object ghost not found");
24 if(manager == null) Debug.Log ("game object Game Manager not found");
25 }
26
27 public void AILogic()
28 {
29 // get current tile
30 Vector3 currentPos = new Vector3(transform.position.x + 0.499f, transform.position.y + 0.499f);
31 currentTile = tiles[manager.Index ((int)currentPos.x, (int)currentPos.y)];
32
33 targetTile = GetTargetTilePerGhost();
34
35 // get the next tile according to direction
36 if(ghost.direction.x > 0) nextTile = tiles[manager.Index ((int)(currentPos.x+1), (int)currentPos.y)];
37 if(ghost.direction.x < 0) nextTile = tiles[manager.Index ((int)(currentPos.x-1), (int)currentPos.y)];
38 if(ghost.direction.y > 0) nextTile = tiles[manager.Index ((int)currentPos.x, (int)(currentPos.y+1))];
39 if(ghost.direction.y < 0) nextTile = tiles[manager.Index ((int)currentPos.x, (int)(currentPos.y-1))];
40
41 if(nextTile.occupied || currentTile.isIntersection)
42 {
43 //---------------------
44 // IF WE BUMP INTO WALL
45 if(nextTile.occupied && !currentTile.isIntersection)
46 {
47 // if ghost moves to right or left and there is wall next tile
48 if(ghost.direction.x != 0)
49 {
50 if(currentTile.down == null) ghost.direction = Vector3.up;
51 else ghost.direction = Vector3.down;
52
53 }
54
55 // if ghost moves to up or down and there is wall next tile
56 else if(ghost.direction.y != 0)
57 {
58 if(currentTile.left == null) ghost.direction = Vector3.right;
59 else ghost.direction = Vector3.left;
60
61 }
62
63 }
64
65 //---------------------------------------------------------------------------------------
66 // IF WE ARE AT INTERSECTION
67 // calculate the distance to target from each available tile and choose the shortest one
68 if(currentTile.isIntersection)
69 {
70
71 float dist1, dist2, dist3, dist4;
72 dist1 = dist2 = dist3 = dist4 = 999999f;
73 if(currentTile.up != null && !currentTile.up.occupied && !(ghost.direction.y < 0)) dist1 = manager.distance(currentTile.up, targetTile);
74 if(currentTile.down != null && !currentTile.down.occupied && !(ghost.direction.y > 0)) dist2 = manager.distance(currentTile.down, targetTile);
75 if(currentTile.left != null && !currentTile.left.occupied && !(ghost.direction.x > 0)) dist3 = manager.distance(currentTile.left, targetTile);
76 if(currentTile.right != null && !currentTile.right.occupied && !(ghost.direction.x < 0)) dist4 = manager.distance(currentTile.right, targetTile);
77
78 float min = Mathf.Min(dist1, dist2, dist3, dist4);
79 if(min == dist1) ghost.direction = Vector3.up;
80 if(min == dist2) ghost.direction = Vector3.down;
81 if(min == dist3) ghost.direction = Vector3.left;
82 if(min == dist4) ghost.direction = Vector3.right;
83
84 }
85
86 }
87
88 // if there is no decision to be made, designate next waypoint for the ghost
89 else
90 {
91 ghost.direction = ghost.direction; // setter updates the waypoint
92 }
93 }
94
95 public void RunLogic()
96 {
97 // get current tile
98 Vector3 currentPos = new Vector3(transform.position.x + 0.499f, transform.position.y + 0.499f);
99 currentTile = tiles[manager.Index ((int)currentPos.x, (int)currentPos.y)];
100
101 // get the next tile according to direction
102 if(ghost.direction.x > 0) nextTile = tiles[manager.Index ((int)(currentPos.x+1), (int)currentPos.y)];
103 if(ghost.direction.x < 0) nextTile = tiles[manager.Index ((int)(currentPos.x-1), (int)currentPos.y)];
104 if(ghost.direction.y > 0) nextTile = tiles[manager.Index ((int)currentPos.x, (int)(currentPos.y+1))];
105 if(ghost.direction.y < 0) nextTile = tiles[manager.Index ((int)currentPos.x, (int)(currentPos.y-1))];
106
107 //Debug.Log (ghost.direction.x + " " + ghost.direction.y);
108 //Debug.Log (ghost.name + ": Next Tile (" + nextTile.x + ", " + nextTile.y + ")" );
109
110 if(nextTile.occupied || currentTile.isIntersection)
111 {
112 //---------------------
113 // IF WE BUMP INTO WALL
114 if(nextTile.occupied && !currentTile.isIntersection)
115 {
116 // if ghost moves to right or left and there is wall next tile
117 if(ghost.direction.x != 0)
118 {
119 if(currentTile.down == null) ghost.direction = Vector3.up;
120 else ghost.direction = Vector3.down;
121
122 }
123
124 // if ghost moves to up or down and there is wall next tile
125 else if(ghost.direction.y != 0)
126 {
127 if(currentTile.left == null) ghost.direction = Vector3.right;
128 else ghost.direction = Vector3.left;
129
130 }
131
132 }
133
134 //---------------------------------------------------------------------------------------
135 // IF WE ARE AT INTERSECTION
136 // choose one available option at random
137 if(currentTile.isIntersection)
138 {
139 List<TileManager.Tile> availableTiles = new List<TileManager.Tile>();
140 TileManager.Tile chosenTile;
141 if(currentTile.up != null && !currentTile.up.occupied && !(ghost.direction.y < 0)) availableTiles.Add (currentTile.up);
142 if(currentTile.down != null && !currentTile.down.occupied && !(ghost.direction.y > 0)) availableTiles.Add (currentTile.down);
143 if(currentTile.left != null && !currentTile.left.occupied && !(ghost.direction.x > 0)) availableTiles.Add (currentTile.left);
144 if(currentTile.right != null && !currentTile.right.occupied && !(ghost.direction.x < 0)) availableTiles.Add (currentTile.right);
145
146 int rand = Random.Range(0, availableTiles.Count);
147 chosenTile = availableTiles[rand];
148 ghost.direction = Vector3.Normalize(new Vector3(chosenTile.x - currentTile.x, chosenTile.y - currentTile.y, 0));
149 //Debug.Log (ghost.name + ": Chosen Tile (" + chosenTile.x + ", " + chosenTile.y + ")" );
150 }
151
152 }
153
154 // if there is no decision to be made, designate next waypoint for the ghost
155 else
156 {
157 ghost.direction = ghost.direction; // setter updates the waypoint
158 }
159 }
160
161
162 TileManager.Tile GetTargetTilePerGhost()
163 {
164 Vector3 targetPos;
165 TileManager.Tile targetTile;
166 Vector3 dir;
167
168 // get the target tile position (round it down to int so we can reach with Index() function)
169 switch(name)
170 {
171 case "blinky": // target = pacman
172 targetPos = new Vector3 (target.position.x+0.499f, target.position.y+0.499f);
173 targetTile = tiles[manager.Index((int)targetPos.x, (int)targetPos.y)];
174 break;
175 case "pinky": // target = pacman + 4*pacman's direction (4 steps ahead of pacman)
176 dir = target.GetComponent<PlayerController>().getDir();
177 targetPos = new Vector3 (target.position.x+0.499f, target.position.y+0.499f) + 4*dir;
178
179 // if pacmans going up, not 4 ahead but 4 up and 4 left is the target
180 // read about it here: http://gameinternals.com/post/2072558330/understanding-pac-man-ghost-behavior
181 // so subtract 4 from X coord from target position
182 if(dir == Vector3.up) targetPos -= new Vector3(4, 0, 0);
183
184 targetTile = tiles[manager.Index((int)targetPos.x, (int)targetPos.y)];
185 break;
186 case "inky": // target = ambushVector(pacman+2 - blinky) added to pacman+2
187 dir = target.GetComponent<PlayerController>().getDir();
188 Vector3 blinkyPos = GameObject.Find ("blinky").transform.position;
189 Vector3 ambushVector = target.position + 2*dir - blinkyPos ;
190 targetPos = new Vector3 (target.position.x+0.499f, target.position.y+0.499f) + 2*dir + ambushVector;
191 targetTile = tiles[manager.Index((int)targetPos.x, (int)targetPos.y)];
192 break;
193 case "clyde":
194 targetPos = new Vector3 (target.position.x+0.499f, target.position.y+0.499f);
195 targetTile = tiles[manager.Index((int)targetPos.x, (int)targetPos.y)];
196 if(manager.distance(targetTile, currentTile) < 9)
197 targetTile = tiles[manager.Index (0, 2)];
198 break;
199 default:
200 targetTile = null;
201 Debug.Log ("TARGET TILE NOT ASSIGNED");
202 break;
203
204 }
205 return targetTile;
206 }
207 }
get current tile
get the next tile according to direction
---------------------
IF WE BUMP INTO WALL
if ghost moves to right or left and there is wall next tile
if ghost moves to up or down and there is wall next tile
---------------------------------------------------------------------------------------
IF WE ARE AT INTERSECTION
calculate the distance to target from each available tile and choose the shortest one
if there is no decision to be made, designate next waypoint for the ghost
ghost.direction = ghost.direction; setter updates the waypoint
get current tile
get the next tile according to direction
Debug.Log (ghost.direction.x + " " + ghost.direction.y);
Debug.Log (ghost.name + ": Next Tile (" + nextTile.x + ", " + nextTile.y + ")" );
---------------------
IF WE BUMP INTO WALL
if ghost moves to right or left and there is wall next tile
if ghost moves to up or down and there is wall next tile
---------------------------------------------------------------------------------------
IF WE ARE AT INTERSECTION
choose one available option at random
Debug.Log (ghost.name + ": Chosen Tile (" + chosenTile.x + ", " + chosenTile.y + ")" );
if there is no decision to be made, designate next waypoint for the ghost
ghost.direction = ghost.direction; setter updates the waypoint
get the target tile position (round it down to int so we can reach with Index() function)
case "blinky": target = pacman
case "pinky": target = pacman + 4*pacman's direction (4 steps ahead of pacman)
if pacmans going up, not 4 ahead but 4 up and 4 left is the target
read about it here: http:gameinternals.compost2072558330understanding-pac-man-ghost-behavior
so subtract 4 from X coord from target position
case "inky": target = ambushVector(pacman+2 - blinky) added to pacman+2